home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
ddj9304.zip
/
1993-APR.ZIP
/
STEREO.ASC
< prev
next >
Wrap
Text File
|
1993-02-17
|
15KB
|
388 lines
_ALGORITHMS FOR STEREOSCOPIC IMAGES_
by Victor Duvanenko and W.E. Robbins
[LISTING ONE]
display_3D_data( proj )
int proj;
{
double Tw[4][4], S[4][4], Td[4][4], Ry[4][4], Per[4][4], tmp[4][4];
double Left[4][4], Right[4][4];
double e_v, /* interocular distance mapped back to the view coord. */
e_w; /* interocular distance mapped back to the world coord. */
printf( "Computing normals for shading. " );
compute_normals(); /* and the dot products for each triangle */
printf( "Done.\n" );
/* Perspective projection must use three steps:
1) Compute normals and project,
2) Divide by W (homogenize)
3) Transform into the device coordinates. */
if ( proj == PERSPECTIVE )
{
/* map physical interocular distance into the view port coordinates. */
e_v = INTEROCULAR_DISTANCE / PIXEL_WIDTH; /* e_v == pixels */
/* map from the viewport coordinate system to the world. */
e_w = e_v / (( x_right_d - x_left_d ) / ( x_right - x_left ));
set_to_identity( Left, 4 );
set_to_identity( Right, 4 );
/* Use the Translate, Project, Translate back model. */
/* Create the Left eye transformation matrix. */
set_to_identity( Tw, 4 ); /* translate the left eye to the origin */
Tw[3][0] = -e_w / 2.0;
matrix_mult( Left, 4, 4, Tw, 4, 4, tmp );
/* Create the perspective projection matrix. */
set_to_identity( Per, 4 );
Per[2][3] = 1.0 / proj_plane; /* 1/d */
Per[3][3] = 0.0;
matrix_mult( tmp, 4, 4, Per, 4, 4, Left );
Tw[3][0] = e_w / 2.0; /* translate back */
matrix_mult( Left, 4, 4, Tw, 4, 4, tmp );
copy_matrix( tmp, Left, 4, 4 );
/* Create the Right eye transformation matrix. */
set_to_identity( Tw, 4 ); /* translate the right eye to the origin */
Tw[3][0] = e_w / 2.0;
matrix_mult( Right, 4, 4, Tw, 4, 4, tmp );
/* Create the perspective projection matrix. */
set_to_identity( Per, 4 );
Per[2][3] = 1.0 / proj_plane; /* 1/d */
Per[3][3] = 0.0;
matrix_mult( tmp, 4, 4, Per, 4, 4, Right );
Tw[3][0] = -e_w / 2.0; /* translate back */
matrix_mult( Right, 4, 4, Tw, 4, 4, tmp );
copy_matrix( tmp, Right, 4, 4 );
#if 0
printf( "Transforming, projecting and homogenizing the image. " );
transform_and_homogenize_image( image, tr_image, Tm );
printf( "Done.\n" );
#endif
}
/* Create the world to device transformation matrix. */
/* Create the translation matrix. Translate only in X and Y. */
set_to_identity( Tw, 4 );
Tw[3][0] = -x_left; Tw[3][1] = -y_bottom; Tw[3][2] = 0.0;
/* Create a uniform scale matrix. */
set_to_identity( S, 4 );
S[0][0] = ( x_right_d - x_left_d ) / ( x_right - x_left );
S[1][1] = ( y_top_d - y_bottom_d ) / ( y_top - y_bottom );
S[2][2] = ( z_back_d - z_front_d ) / ( z_back - z_front );
matrix_mult( Tw, 4, 4, S, 4, 4, tmp );
copy_matrix( tmp, Tw, 4, 4 );
/* Create the translation matrix. Translate only in X and Y. */
set_to_identity( Td, 4 );
Td[3][0] = x_left_d; Td[3][1] = y_bottom_d; Td[3][2] = 0.0;
matrix_mult( Tw, 4, 4, Td, 4, 4, tmp );
copy_matrix( tmp, Tw, 4, 4 );
/* Since device/screen origin on LEX/90 is in upper left, we need to reflect
Y and translate by screen height to place device origin in bottom left.*/
set_to_identity( Ry, 4 );
Ry[1][1] = -1.0;
matrix_mult( Tw, 4, 4, Ry, 4, 4, tmp );
copy_matrix( tmp, Tw, 4, 4 );
set_to_identity( Td, 4 );
Td[3][1] = SCREEN_HEIGHT;
matrix_mult( Tw, 4, 4, Td, 4, 4, tmp );
copy_matrix( tmp, Tw, 4, 4 );
/* Now, Tw has the world to device/screen transformation matrix. */
if ( proj == PARALLEL )
{
/* Beautiful!!! Perform a single transformation of the image (for
parallel projection). */
printf( "Transforming, projecting and mapping the image onto screen." );
matrix_mult( Tm, 4, 4, Tw, 4, 4, tmp );
copy_matrix( tmp, Tm, 4, 4 );
show_matrix( Tm, 4, 4 );
transform_and_homogenize_image( image, tr_image, Tm );
printf( "Done.\n" );
printf( "Rendering the image. " );
render_image( LEFT_EYE ); printf( "Done.\n" );
}
if ( proj == PERSPECTIVE )
{
printf( "Transforming, projecting, homogenizing and mapping the " );
printf( "Left image onto screen. " );
matrix_mult( Tm, 4, 4, Left, 4, 4, tmp );
matrix_mult( tmp, 4, 4, Tw, 4, 4, Left );
printf( "Left eye transformation matrix.\n" );
show_matrix( Left, 4, 4 );
transform_and_homogenize_image( image, tr_image, Left );
printf( "Done.\n" );
printf( "Rendering the Left eye image. " );
render_image( LEFT_EYE ); printf( "Done.\n" );
printf( "Transforming, projecting, homogenizing and mapping the " );
printf( "Right image onto screen. " );
matrix_mult( Tm, 4, 4, Right, 4, 4, tmp );
matrix_mult( tmp, 4, 4, Tw, 4, 4, Right );
/* Move the right eye view into the lower half of the buffer. */
set_to_identity( Tw, 4 );
Tw[3][1] = SCREEN_HEIGHT; /* move in device coord */
matrix_mult( Right, 4, 4, Tw, 4, 4, tmp );
copy_matrix( tmp, Right, 4, 4 );
printf( "Right eye transformation matrix.\n" );
show_matrix( Right, 4, 4 );
transform_and_homogenize_image( image, tr_image, Right );
printf( "Done.\n" );
dszom( &0, &512, &1 ); /* look at the lower half */
printf( "Rendering the Right eye image. " );
render_image( RIGHT_EYE ); printf( "Done.\n" );
}
}
[LISTING TWO]
make_composite_viewing_matrix( proj )
int proj; /* PARALLEL or PERSPECTIVE */
{
double p1[4], p2[4], p3[4], p_tmp[4];
double T[4][4], Rx[4][4], Ry[4][4], Rz[4][4], C_tmp1[4][4], C_tmp2[4][4];
double Per[4][4], d1, d2, d12, cos_ang, sin_ang;
/* Initialize the three points */
p1[0] = eye_pt.x; p1[1] = eye_pt.y; p1[2] = eye_pt.z; p1[3] = 1.0;
p2[0] = p2[1] = p2[2] = 0.0; p2[3] = 1.0;
p3[0] = p1[0] + vup.x; p3[1] = p1[1] + vup.y; p3[2] = p1[2] + vup.z;
p3[3] = 1.0;
/* Magnitude of vector p1->p2 */
d12 = sqrt( p1[0] * p1[0] + p1[1] * p1[1] + p1[2] * p1[2] );
/* Create the translation matrix. */
set_to_identity( T, 4 );
T[3][0] = -p1[0]; T[3][1] = -p1[1]; T[3][2] = -p1[2];
/* Translate the three points p1, p2, and p3 to the origin. */
matrix_mult( p1, 1, 4, T, 4, 4, p_tmp );
copy_matrix( p_tmp, p1, 1, 4 );
matrix_mult( p2, 1, 4, T, 4, 4, p_tmp );
copy_matrix( p_tmp, p2, 1, 4 );
matrix_mult( p3, 1, 4, T, 4, 4, p_tmp );
copy_matrix( p_tmp, p3, 1, 4 );
d1 = sqrt( p2[0] * p2[0] + p2[2] * p2[2] ); /* length of projection */
cos_ang = -p2[2] / d1;
sin_ang = p2[0] / d1;
/* Create the rotation about Y-axis matrix. */
set_to_identity( Ry, 4 );
Ry[0][0] = cos_ang; Ry[0][2] = -sin_ang;
Ry[2][0] = sin_ang; Ry[2][2] = cos_ang;
/* Rotate the three points p2, and p3 about the Y-axis. */
/* p1 is at the origin after translation => no need to rotate. */
matrix_mult( p2, 1, 4, Ry, 4, 4, p_tmp );
copy_matrix( p_tmp, p2, 1, 4 );
matrix_mult( p3, 1, 4, Ry, 4, 4, p_tmp );
copy_matrix( p_tmp, p3, 1, 4 );
cos_ang = -p2[2] / d12;
sin_ang = -p2[1] / d12;
/* Create the rotation about X-axis matrix. */
set_to_identity( Rx, 4 );
Rx[1][1] = cos_ang; Rx[1][2] = sin_ang;
Rx[2][1] = -sin_ang; Rx[2][2] = cos_ang;
/* Rotate the three points p2, and p3 about the X-axis. */
matrix_mult( p2, 1, 4, Rx, 4, 4, p_tmp );
copy_matrix( p_tmp, p2, 1, 4 );
matrix_mult( p3, 1, 4, Rx, 4, 4, p_tmp );
copy_matrix( p_tmp, p3, 1, 4 );
/* Sanity check. */
printf( "The view vector should be [ %lf %lf %lf %lf ]\n", 0.0, 0.0, -d12,
1.0 );
printf( "The view vector is [ %lf %lf %lf %lf ]\n", p2[0], p2[1],
p2[2], p2[3] );
d2 = sqrt( p3[0] * p3[0] + p3[1] * p3[1] );
cos_ang = p3[1] / d2;
sin_ang = p3[0] / d2;
/* Create the rotation about Z-axis matrix. */
set_to_identity( Rz, 4 );
Rz[0][0] = cos_ang; Rz[0][1] = sin_ang;
Rz[1][0] = -sin_ang; Rz[1][1] = cos_ang;
/* At this point the translation, and all rotation matrices are known
and need to be combined into a single transformaation matrix. */
matrix_mult( T, 4, 4, Ry, 4, 4, C_tmp1 );
matrix_mult( C_tmp1, 4, 4, Rx, 4, 4, C_tmp2 );
matrix_mult( C_tmp2, 4, 4, Rz, 4, 4, C_tmp1 );
copy_matrix( C_tmp1, Tm, 4, 4 );
}
[LISTING THREE]
void compute_normals()
{
register i, j;
point_3D_t p11_p21, p11_p22, p11_p12, cross_a, cross_b;
double d, dx; /* stepping distance (dx = dy) */
double dx_sqrd; /* dx^2 */
int num_lines;
point_3D_t na, nb; /* normals to triangle A and B */
dx = scan_sz / num_samples;
num_lines = MIN( num_samples, MAX_IMAGE_SIZE );
num_lines--;
dx_sqrd = dx * dx;
for( i = 0; i < num_lines; i++ )
for( j = 0; j < num_lines; j++ )
{
#if DEBUG
printf( "P11 %f %f %f\n", image[i][j].x, image[i][j].y,
image[i][j].z );
printf( "P21 %f %f %f\n", image[i+1][j].x, image[i+1][j].y,
image[i+1][j].z );
printf( "P12 %f %f %f\n", image[i][j+1].x, image[i][j+1].y,
image[i][j+1].z );
printf( "P22 %f %f %f\n", image[i+1][j+1].x, image[i+1][j+1].y,
image[i+1][j+1].z );
#endif
p11_p21.z = image[ i + 1 ][ j ].z - image[ i ][ j ].z;
p11_p22.z = image[ i + 1 ][ j + 1 ].z - image[ i ][ j ].z;
p11_p12.z = image[ i ][ j + 1 ].z - image[ i ][ j ].z;
#if DEBUG
printf( "dz11_21 = %f, dz11_22 = %f, dz11_12 = %f\n",
p11_p21.z, p11_p22.z, p11_p12.z );
#endif
/* It's possible to eliminate one more multiplication in the
computations below. */
na.x = dx * ( p11_p21.z - p11_p22.z );
na.y = dx * p11_p21.z;
na.z = dx_sqrd;
#if DEBUG
printf( "Na %f %f %f\n", na.x, na.y, na.z );
#endif
nb.x = (-dx) * p11_p12.z;
nb.y = dx * ( p11_p22.z - p11_p12.z );
nb.z = dx_sqrd;
#if DEBUG
printf( "Nb %f %f %f\n", nb.x, nb.y, nb.z );
#endif
/* Normalize the normal vectors, since the intensity will be
proportional to the angle between light source and the normal. */
d = sqrt((double)( na.x * na.x + na.y * na.y + na.z * na.z ));
na.x = na.x / d;
na.y = na.y / d;
na.z = na.z / d;
#if DEBUG
printf( "Na %f %f %f\n", na.x, na.y, na.z );
#endif
d = sqrt((double)( nb.x * nb.x + nb.y * nb.y + nb.z * nb.z ));
nb.x = nb.x / d;
nb.y = nb.y / d;
nb.z = nb.z / d;
#if DEBUG
printf( "Nb %f %f %f\n", nb.x, nb.y, nb.z );
#endif
/* Compute the dot product between the light source vector and
the normals (== to the angle between two unit vectors ).
-1 <= cos( theta ) <= 1, which will be very useful. */
image[ i ][ j ].sha = light_source.x * na.x + light_source.y * na.y +
light_source.z * na.z;
image[ i ][ j ].shb = light_source.x * nb.x + light_source.y * nb.y +
light_source.z * nb.z;
}
}
[LISTING FOUR]
transform_and_homogenize_image( s, d, tm )
point_3D_ex_t s[][ MAX_IMAGE_SIZE ], d[][ MAX_IMAGE_SIZE ];
double *tm; /* transformation matrix */
{
register i, j;
int num_lines;
double p[4]; /* the point to be transformed */
double t[4], inv_W;
num_lines = MIN( num_samples, MAX_IMAGE_SIZE );
for( i = 0; i < num_lines; i++ )
for( j = 0; j < num_lines; j++ )
{
p[0] = s[i][j].x; p[1] = s[i][j].y;
p[2] = s[i][j].z; p[3] = 1.0;
matrix_mult( p, 1, 4, tm, 4, 4, t );
if ( t[3] != 1.0 ) /* divide by W (homogenize) */
{
inv_W = 1.0 / t[3];
t[0] *= inv_W; t[1] *= inv_W; t[2] *= inv_W;
}
d[i][j].x = t[0]; d[i][j].y = t[1]; d[i][j].z = t[2];
d[i][j].sha = s[i][j].sha; d[i][j].shb = s[i][j].shb;
}
}
[LISTING FIVE]
render_image( y )
int y;
{
register i, j;
int num_lines;
short v[6], intensity;
num_lines = MIN( num_samples, MAX_IMAGE_SIZE );
num_lines--;
for( i = 0; i < num_lines; i++ )
for( j = 0; j < num_lines; j++ )
{
v[0] = ROUND( tr_image[ i ][ j ].x );
v[1] = ROUND( tr_image[ i ][ j ].y );
v[2] = ROUND( tr_image[ i + 1 ][ j ].x );
v[3] = ROUND( tr_image[ i + 1 ][ j ].y );
v[4] = ROUND( tr_image[ i + 1 ][ j + 1 ].x );
v[5] = ROUND( tr_image[ i + 1 ][ j + 1 ].y );
/* Render triangle A */
intensity = ROUND( tr_image[ i ][ j ].sha * (double)(NUM_SHADES - 1));
if ( intensity > ( NUM_SHADES - 1 ))
intensity = NUM_SHADES - 1; /* saturate */
if ( intensity < 0 )
{
#if 0
printf( "Triangle A, intensity = %d\n", intensity );
printf( "v11.x = %f, v11.y = %f, v11.z = %f\n",
image[i][j].x, image[i][j].y, image[i][j].z );
printf( "v21.x = %f, v21.y = %f, v21.z = %f\n",
image[i+1][j].x, image[i+1][j].y, image[i+1][j].z );
printf( "v22.x = %f, v22.y = %f, v22.z = %f\n",
image[i+1][j+1].x, image[i+1][j+1].y, image[i+1][j+1].z );
#endif
intensity = 0;
}
if ( clip_to_viewport( v, 6, y ) == ACCEPT )
dspoly( &intensity, v, &6 );
v[2] = ROUND( tr_image[ i ][ j + 1 ].x );
v[3] = ROUND( tr_image[ i ][ j + 1 ].y );
/* Render triangle B */
intensity = ROUND( tr_image[ i ][ j ].shb * (double)( NUM_SHADES-1));
if ( intensity > ( NUM_SHADES - 1 ))
intensity = NUM_SHADES - 1; /* saturate */
if ( intensity < 0 ) intensity = 0;
if ( clip_to_viewport( v, 6, y ) == ACCEPT )
dspoly( &intensity, v, &6 );
}
}
[LISTING SIX]
display_3D_data( proj )
int proj;
{
double Tw[4][4], S[4][4], Td[4][4], Ry[4][4], Per[4][4], tmp[4][4];
double Left[4][4], Right[4][4];
double e_v, /* interocular distance mapped back to the view coord. */
e_w; /* interocular distance mapped back to the world coord. */
printf( "Computing normals for shading. " );
compute_normals(); /* and the dot products for each triangle */
printf( "Done.\n" );